

import ikelib.ConfigString;
import ikelib.Field;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.Iterator;
import java.util.LinkedList;

/****************************************************************
 sample csvconf.ini  

 ********************************************************** */
/**
 * ＣＳＶインポートのためのパラメータを扱うクラス。
 *  パラメータのデータ構造を定義し、パラメータファイル、パラメータ文字列と相互変換する。
 *  
 * @author ikechan
 *
 */
public class CsvImportParameter {
	
	private LinkedList<CsvImportConfigElement> Param = new LinkedList<CsvImportConfigElement>();
	/**
	 * ＣＳＶインポートのためのパラメータのうち、CH毎のパラメータを表す。
	 * 
	 * @author ikechan
	 *
	 */
	public class CsvImportFieldElement {
		public int    Column=0;
		public int    Chid =0;
		public double Factor=0.0;
		CsvImportFieldElement(){};
		CsvImportFieldElement(CsvImportFieldElement e){
			Column = e.Column;
			Chid = e.Chid;
			Factor = e.Factor;
		};
		/**
		 * Deepなコピー
		 * @param e
		 */
		void copy(CsvImportFieldElement e){
			Column = e.Column;
			Chid = e.Chid;
			Factor = e.Factor;
		}
		
	}
	/**
	 * CSVインポートのＣＯＮＦＩＧ（パラメータ一式）を表すクラス。
	 * 　　パラメータファイルは、このＣＯＮＦＩＧを複数保持している。
	 * @author ikechan
	 *
	 */
	public class CsvImportConfigElement{
		public String Name = "NoName";
		public int SampleRate = 1;
		public int DateColumn = -1;
		public int IntervalColumn = -1;
		public int IgnoreHeader = 0;
		public LinkedList<CsvImportFieldElement> Field = new LinkedList<CsvImportFieldElement>();
		CsvImportConfigElement(){};
	}
	/**
	 * 指定のCONFIGセクションから CsvImportFieldElementのLinkedListを得る。
	 * @param cur　String ＣＯＮＦＩＧセクション名
	 * @return　 LinkedList<CsvImportFieldElement>
	 */
	public  LinkedList<CsvImportFieldElement>  getFieldElement(String cur){
		CsvImportConfigElement c=getConfig( cur);
		return c.Field;
	}
	/**
	 * curで示されるＣＯＮＦＩＧのCsvImportFieldElementをセットする。
	 *  ＣＨ ＩＤが既存なら書き換える、なければ新規に追加する。
	 * @param cur　Ｓｔｒｉｎｇ　ＣＯＮＦＩＧ名
	 * @param f　セットしたい CsvImportFieldElement
	 */
	public void setFieldElement(String cur,CsvImportFieldElement f){
		CsvImportConfigElement c=getConfig( cur);
		Iterator<CsvImportFieldElement> ite = c.Field.iterator();
		while(ite.hasNext()){
			CsvImportFieldElement e = ite.next();
			if(e.Chid == f.Chid){
				e.Column = f.Column;
				e.Factor = e.Factor;
			}
			else{
				e.copy(f);
			}
		}
	}
	/**
	 * デフォルトのcsvconf.iniを作成する
	 *  
	 * @param file String 作成したいfile名
	 */
	private void makeDefaultCsvConf(String file){
		String str = new String();
		try {
			InputStream is = getClass().getResourceAsStream("/default_csvconf.ini");
			BufferedReader reader = new BufferedReader(new InputStreamReader(is,"UTF-8"));
			String line;
			while((line = reader.readLine()) != null) {
				str += new String(line);
				str += "\r\n";
			}
		} catch(Exception e) {
			e.printStackTrace();
		}
		try {
			BufferedWriter br = new BufferedWriter(new FileWriter(file));
			br.write(str);
			br.flush();
			br.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	/**
	 * fileからCSVインポートパラメータ（複数）をロードする。
	 * @param file
	 * @return
	 */
	public boolean load(String file){
		
		Param = new LinkedList<CsvImportConfigElement>();
		CsvImportConfigElement conf = new CsvImportConfigElement();;
		CsvImportFieldElement  field = new CsvImportFieldElement();
		String line = null;
		int linecount = 0;
		int ph=0;
		File conffile = new File(file);
		if(!conffile.isFile()){
			makeDefaultCsvConf(file);
		}
		readFromFile(file, conf, field, line, linecount, ph);
		String[] name = getConfName();
		if(name.length<1){
			makeDefaultCsvConf(file);
			readFromFile(file, conf, field, line, linecount, ph);
		//	String[] name2 = getConfName();
		}
		return true;
	}
	
	private boolean readFromFile(String file, CsvImportConfigElement conf,
			CsvImportFieldElement field, String line, int linecount, int ph) {
		
		try {
			BufferedReader br = new BufferedReader(new FileReader(file));
			
			while((line = br.readLine()) != null){
				line = ConfigString.RemoveComment(line);
				linecount++;
				if(line==null) continue;
				if(line.length()==0) continue;
				String[] tok = line.split("=");
				for(int i=0;i<tok.length;i++) tok[i] = tok[i].trim();
				switch(ph){
				case 0:	// CONFIG { 待ち
					if(tok[0].startsWith("CONFIG")){
						ph = 1;
						conf = new CsvImportConfigElement();
					}
					break;
				case 1: // CONFIGの中
					if(tok.length==2){
						if(tok[0].compareTo("Name")==0){
							conf.Name= new String(tok[1]);
						}
						else if(tok[0].compareTo("SampleRate")==0){
							conf.SampleRate = Integer.valueOf(tok[1]);
						}
						else if(tok[0].compareTo("DateColumn")==0){
							conf.DateColumn = Integer.valueOf(tok[1]);
							
						}
						else if(tok[0].compareTo("IntervalColumn")==0){
							conf.IntervalColumn = Integer.valueOf(tok[1]);
						}
						else if(tok[0].compareTo("IgnoreHeader")==0){
							conf.IgnoreHeader = Integer.valueOf(tok[1]);
						}
						else{
							System.err.println(String.format("csvconf Error (%d) : %s ",linecount,line));
							break;
						}
					}
					else{
						if(tok[0].compareTo("}") == 0){
							ph = 0;
							Param.add(conf);
						}
						else if(tok[0].startsWith("FIELD")){
							ph = 2;
							field = new  CsvImportFieldElement();
						}
						else{
							System.err.println(String.format("csvconf Error (%d) : %s ",linecount,line));
						}
					}
					break;
				case 2: //FIELDの中
					if(tok.length==2){
						if(tok[0].compareTo("Column")==0){
							field.Column = Integer.valueOf(tok[1]);
							
						}
						else if(tok[0].compareTo("Channel")==0){
							field.Chid = Integer.valueOf(tok[1],16);
							
						}
						else if(tok[0].compareTo("Factor")==0){
							field.Factor = Double.valueOf(tok[1]);
							
						}
						else {
							System.err.println(String.format("csvconf Error (%d) : %s ",linecount,line));
							break;
						}
					}
					else{
						if(tok[0].compareTo("}") == 0){
							ph = 1;
							conf.Field.add(field);
						}
						else{
							System.err.println(String.format("csvconf Error (%d) : %s ",linecount,line));
						}
					}
					break;
				}
			}
			br.close();
			
		} catch (FileNotFoundException e) {
			System.out.println(String.format("Create file %s in winchkg.jar directory. Then copy contents from Help.",file));
			System.err.println(String.format("csvconf File not found Error : %s ",file));
			return false;
		} catch (IOException e) {
			e.printStackTrace();
			System.err.println(String.format("csvconf IO Error (%d) : %s ",linecount,line));
			return false;
		} catch(NumberFormatException e){
			System.err.println(String.format("csvconf Number format Error (%d) : %s ",linecount,line));
			return false;
		}
		return true;
	}
	/**
	 * CONF セクションの名前のリストを返す
	 * @return String[] ＣＯＮＦＩＧ名の配列
	 */
	 
	public String[] getConfName() {
		String[] ret = new String[Param.size()];
		Iterator<CsvImportConfigElement> ite = Param.iterator();
		int i=0;
		while(ite.hasNext()){
			CsvImportConfigElement ele = ite.next();
			ret[i++] = new String(ele.Name);
		}
		return ret;
	}
	/*
	 * 
	 */
	/**
	 * curなＣＯＮＦＩＧのCsvImportConfigElement を返す
	 * @param cur　String ＣＯＮＦＩＧ名
	 * @return　CsvImportConfigElement　なければ null
	 */
	public CsvImportConfigElement getConfig(String cur) {
		if(cur==null || cur.length()<=0) return null;
		Iterator<CsvImportConfigElement> ite = Param.iterator();
		while(ite.hasNext()){
			CsvImportConfigElement ele = ite.next();
			if(ele.Name.compareTo(cur)==0){
				return ele;
			}
		}
		return null;
	}
	/**
	 *  curなＣＯＮＦＩＧ の中身を表す文字列を返す
	 * @param cur　CONFIG名
	 * @return　パラメータのダンプ
	 */
	public String getConfigAsText(String cur) {
		CsvImportConfigElement c=getConfig( cur);
		if(c==null) return null;
		String ret = "CONFIG { \n";
		ret += String.format("\t Name = %s\n", c.Name);
		ret += String.format("\t SampleRate = %d\n", c.SampleRate);
		ret += String.format("\t DateColumn = %d\n", c.DateColumn);
		ret += String.format("\t IntervalColumn = %d\n", c.IntervalColumn);
		ret += String.format("\t IgnoreHeader = %d\n", c.IgnoreHeader);
		
		Iterator<CsvImportFieldElement> ite = c.Field.iterator();
		while(ite.hasNext()){
			CsvImportFieldElement e = ite.next();
			ret += ("\t FIELD {\n");
			ret += String.format("\t\t   Column = %d\n", e.Column);
			ret += String.format("\t\t   Channel = %s\n", String.format("%04x", e.Chid));
			ret += String.format("\t\t   Factor = %f\n", e.Factor);
			ret += "\t }\n";
		};
		ret += " }\n";
		ret = ret.replace("\t","    ");
		return ret;
	}
}
